#pragma once

namespace SD_Tools
{
	class External
	{
	private:
	public:
	private:
		static bool DataCompare(const BYTE* Buffer, const BYTE* Mask1, const char* Mask2);
	public:
		static DWORD GetPIdByProcessName(const wchar_t* Name);
		static int GetModuleList(HANDLE ProcessHandle, HMODULE** Out);
		static DWORD AllocCodeCave(HANDLE ProcessHandle, int NumberOfBytes);
		static DWORD AllocMemoryCave(HANDLE ProcessHandle, int NumberOfBytes);
		static BOOL ReleaseMemoryCave(HANDLE ProcessHandle, DWORD Address);
		static BOOL ReadMemory(HANDLE ProcessHandle, DWORD Address, void* Out, int NumberOfBytes);
		static BOOL WriteMemory(HANDLE ProcessHandle, DWORD Address, void* Buffer, int NumberOfBytes);
		static BOOL ChangeProtection(HANDLE ProcessHandle, DWORD NewProtection, DWORD Address, DWORD Size, DWORD* Old = 0);
		static DWORD GetModuleBase(const DWORD ProcessId, const wchar_t* ModuleName);
		static bool InjectDll(HANDLE ProcessHandle, wchar_t* DllPath, bool CleanUp = true);
		static HANDLE OpenProcessById(DWORD AccessRights, DWORD ProcessId);
		static DWORD FindPattern(HANDLE ProcessHandle, DWORD Address, DWORD Length, unsigned char* Mask1, char* Mask2);
		static DWORD GetModuleSize(DWORD ProcessId, wchar_t* ModuleName);
		template<typename T> static DWORD DerefPointer(HANDLE ProcessHandle, DWORD Base, T* Out, int Amount, ...);
		template<typename T> static DWORD DerefPointer_s(HANDLE ProcessHandle, DWORD Base, T* Out, int Amount, ...);
	};
	
	//************************************
	// Method:    GetPIdByProcessName
	// Profit:	Returns the ProcessId of the given Processname
	// FullName:  SD_Tools::External::GetPIdByProcessName
	// Returns:   DWORD as the ProcessID
	// Notes:
	// -Returns 0 upon Failure
	//************************************
	DWORD External::GetPIdByProcessName( const wchar_t* Name )
	{
		PROCESSENTRY32 entry;
		entry.dwSize = sizeof(PROCESSENTRY32);
		DWORD ProcessID = 0;
		HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
		if (Process32First(snapshot, &entry) == TRUE)
		{
			while (Process32Next(snapshot, &entry) == TRUE)
			{
				if (_wcsicmp(entry.szExeFile, Name) == 0)
				{
					ProcessID = entry.th32ProcessID;
				}
			}
		}
		CloseHandle(snapshot);
		return ProcessID;
	}

	//************************************
	// Method:    GetModuleList
	// Profit:	Creates a list of all Modules in the given process
	// FullName:  SD_Tools::External::GetModuleList
	// Returns:   int as the Number of HMODULES listed
	// Notes:
	// -Returns 0 upon Failure
	// ======WARNING======
	// -Allocates a HMODULE-list in the needed size by itself!
	// -Call delete[] on your HMODULE* after use!
	// ======WARNING======
	//************************************
	int External::GetModuleList( HANDLE ProcessHandle, HMODULE** Out )
	{
		DWORD ArraySize;
		EnumProcessModules(ProcessHandle, *Out, 0, &ArraySize);
		if (!ArraySize)
		{
			return 0;
		}
		*Out = new HMODULE[ArraySize/sizeof(HMODULE)];
		if (!EnumProcessModules(ProcessHandle, *Out, ArraySize, &ArraySize))
		{
			return 0;
		}
		return ArraySize/sizeof(HMODULE);
	}

	//************************************
	// Method:    AllocCodeCave
	// Profit:	Allocates a CodeCave in the given Process
	// FullName:  SD_Tools::External::AllocCodeCave
	// Returns:   DWORD The allocated Cave - Success is Nonzero
	// Notes:
	// -Returns 0 upon Failure
	// -Is just a Wrapper for VirtualAllocEx
	// -VirtualAllocEx gets called with "NULL" as desired Address and "MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE" for flags
	// -visit http://msdn.microsoft.com/en-us/library/windows/desktop/aa366890 for further documentation
	//************************************
	DWORD External::AllocCodeCave(HANDLE ProcessHandle, int NumberOfBytes)
	{
		return (DWORD) VirtualAllocEx(ProcessHandle, NULL, NumberOfBytes, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	}

	//************************************
	// Method:    AllocMemoryCave
	// Profit:	Allocates a MemoryCave in the given Process
	// FullName:  SD_Tools::External::AllocMemoryCave
	// Returns:   DWORD The allocated Cave - Success is Nonzero
	// Notes:
	// -Returns 0 upon Failure
	// -Is just a Wrapper for VirtualAllocEx
	// -VirtualAllocEx gets called with "NULL" as desired Address and "MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE" for flags
	// -visit http://msdn.microsoft.com/en-us/library/windows/desktop/aa366890 for further documentation
	//************************************
	DWORD External::AllocMemoryCave(HANDLE ProcessHandle, int NumberOfBytes)
	{
		return (DWORD) VirtualAllocEx(ProcessHandle, NULL, NumberOfBytes, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
	}

	//************************************
	// Method:    ReleaseMemoryCave
	// Profit:	Releases a Memory/CodeCave in the given Process
	// FullName:  SD_Tools::External::ReleaseMemoryCave
	// Returns:   BOOL Success is Nonzero
	// Notes:
	// -Returns 0 upon Failure
	// -Is just a Wrapper for VirtualFreeEx
	// -VirtualFreeEx gets called with "0" as Size and "MEM_RELEASE" for flags
	// -visit http://msdn.microsoft.com/en-us/library/windows/desktop/aa366894 for further documentation
	//************************************
	BOOL External::ReleaseMemoryCave( HANDLE ProcessHandle, DWORD Address )
	{
		return VirtualFreeEx(ProcessHandle, (void*) Address, 0, MEM_RELEASE);
	}

	//************************************
	// Method:    ReadMemory
	// Profit:	Reads Memory in the given Process at the given Address
	// FullName:  SD_Tools::External::ReadMemory
	// Returns:   BOOL Success is Nonzero
	// Notes:
	// -Returns 0 upon Failure
	// -Is just a Wrapper for ReadProcessMemory
	// -visit http://msdn.microsoft.com/de-de/library/aa915312 for further documentation
	//************************************
	BOOL External::ReadMemory(HANDLE ProcessHandle, DWORD Address, void* Out, int NumberOfBytes)
	{
		return ReadProcessMemory(ProcessHandle, (LPVOID) Address, Out, NumberOfBytes, 0);
	}

	//************************************
	// Method:    WriteMemory
	// Profit:	  Writes Memory in the given Process at the given Address
	// FullName:  SD_Tools::External::WriteMemory
	// Returns:   BOOL Success is Nonzero
	// Notes:
	// -Returns 0 upon Failure
	// -Is just a Wrapper for WriteProcessMemory
	// -visit http://msdn.microsoft.com/de-de/library/aa909195 for further documentation
	//************************************
	BOOL External::WriteMemory(HANDLE ProcessHandle, DWORD Address, void* Buffer, int NumberOfBytes)
	{
		return WriteProcessMemory(ProcessHandle, (void*) Address, Buffer, NumberOfBytes, 0);
	}

	//************************************
	// Method:    ChangeProtection
	// Profit:	  Changes the Protection in the given Process at the given Address with the given NewProtection
	// FullName:  SD_Tools::External::ChangeProtection
	// Returns:   BOOL Success is Nonzero
	// Notes:
	// -Returns 0 upon Failure
	// -Is just a Wrapper for VirtualProtectEx
	// -visit http://msdn.microsoft.com/en-us/library/windows/desktop/aa366899 for further documentation
	//************************************
	BOOL External::ChangeProtection( HANDLE ProcessHandle, DWORD NewProtection, DWORD Address, DWORD Size, DWORD* Old /*= 0*/ )
	{
		return VirtualProtectEx(ProcessHandle, (void*)Address, Size, NewProtection, Old);
	}

	//************************************
	// Method:    GetModuleBase
	// Profit:	  Returns the Base of the given Module in the given Process
	// FullName:  SD_Tools::External::GetModuleBase
	// Returns:   DWORD The Dll-Base - Success is Nonzero
	// Notes:
	// -Returns 0 upon Failure
	// -Acts similar to GetModuleHandle
	//************************************
	DWORD External::GetModuleBase(const DWORD ProcessId, const wchar_t* ModuleName)
	{
		HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);
		if (!hSnap) 
		{
			return 0;
		}

		MODULEENTRY32 me;
		me.dwSize = sizeof(MODULEENTRY32);

		DWORD dwReturn = 0;

		if (Module32First(hSnap, &me)) 
		{
			while (Module32Next(hSnap, &me)) 
			{
				if (lstrcmpi(me.szModule, ModuleName) == 0) 
				{
					dwReturn = (DWORD)me.modBaseAddr;
					break;
				}
			}
		}
		CloseHandle(hSnap);
		return dwReturn;
	}

	//************************************
	// Method:    InjectDll
	// Profit:	  Injects the given DLL in the given Process
	// FullName:  SD_Tools::External::InjectDll
	// Returns:   bool Success is true
	// Notes:
	// -Returns false upon Failure
	// -CleanUp will wait for the Loadlibrary return and will release the allocated Cave
	// -Calls LoadLibraryW with CreateRemoteThread in the Target Process to let it load the dll
	//************************************
	bool External::InjectDll( HANDLE ProcessHandle, wchar_t* DllPath, bool CleanUp /*= true*/ )
	{
		DWORD RemoteString;
		DWORD LoadLibAddy;

		LoadLibAddy = (DWORD) GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
		RemoteString = AllocMemoryCave(ProcessHandle, (wcslen(DllPath)+1)*2);
		WriteMemory(ProcessHandle, RemoteString, DllPath, (wcslen(DllPath)+1)*2);
		HANDLE RemoteThread = CreateRemoteThread(ProcessHandle, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (void*)RemoteString, NULL, NULL);
		if (RemoteThread == INVALID_HANDLE_VALUE)
		{
			CloseHandle(RemoteThread);
			return false;
		}
		if (CleanUp)
		{
			WaitForSingleObject(RemoteThread, INFINITE);
			ReleaseMemoryCave(ProcessHandle, RemoteString);
		}
		CloseHandle(RemoteThread);

		return true;
	}

	//************************************
	// Method:    OpenProcessById
	// Profit:	  Opens the given Process with the given AccessRights
	// FullName:  SD_Tools::External::OpenProcessById
	// Returns:   HANDLE to the opened Process
	// Notes:
	// -Returns 0 upon Failure
	// -Is just a wrapper for OpenProcess
	// -You must close the returned Handle
	// -Visit http://msdn.microsoft.com/en-us/library/ms684320  for further documentation
	//************************************
	HANDLE External::OpenProcessById( DWORD AccessRights, DWORD ProcessId )
	{
		return OpenProcess(AccessRights, false, ProcessId);
	}

	bool External::DataCompare( const BYTE* Buffer, const BYTE* Mask1, const char* Mask2 )
	{
		for(; *Mask2; ++Mask2, ++Buffer, ++Mask1)
		{
			if(*Mask2 == 'x' && *Buffer != *Mask1 )
			{
				return false;
			}
		}
		return true;
	}

	//************************************
	// Method:    FindPattern
	// Profit:	  Finds a given Pattern in the given Process
	// FullName:  SD_Tools::External::FindPattern
	// Returns:   DWORD Address of the found Pattern - Success is Nonzero
	// Notes:
	// -Returns 0 upon failure
	// -Slooooooooooooooooooow
	// -UNTESTED!
	//************************************
	DWORD External::FindPattern( HANDLE ProcessHandle, DWORD Address, DWORD Length, unsigned char* Mask1, char* Mask2 )
	{
		BYTE* Buffer = new BYTE[Length];
		ReadProcessMemory(ProcessHandle, (void*)Address, Buffer, Length, NULL);

		for(DWORD i = 0; i < Length; i++)
		{
			if(DataCompare((BYTE*)(Address + i), Mask1, Mask2))
			{
				delete Buffer;
				return Address + i;
			}
		}
		delete Buffer;
		return 0;
	}

	//************************************
	// Method:    GetModuleSize
	// Profit:	  Gets the size of the given Module
	// FullName:  SD_Tools::External::GetModuleSize
	// Returns:   DWORD
	// Notes:
	// -None
	//************************************
	DWORD External::GetModuleSize( DWORD ProcessId, wchar_t* ModuleName )
	{
		HANDLE hSnap;
		MODULEENTRY32 xModule;
		hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessId);
		xModule.dwSize = sizeof(MODULEENTRY32);
		if (Module32First(hSnap, &xModule))
		{
			while (Module32Next(hSnap, &xModule))
			{
				if (wcscmp(xModule.szModule, ModuleName) == 0)
				{
					CloseHandle(hSnap);
					return (DWORD)xModule.modBaseSize;
				}
			}
		}
		CloseHandle(hSnap);
		return 0;
	}

	//************************************
	// Method:    DerefPointer
	// Profit:	  Derefs a given MultiPointer
	// FullName:  SD_Tools::External<T>::DerefPointer
	// Returns:   DWORD the Adress of the last Deref
	// Notes:
	// -A '_s' Version is available which will check for NULL-Pointers in the deref Processing
	//************************************
	template<typename T> DWORD SD_Tools::External::DerefPointer(HANDLE ProcessHandle, DWORD Base, T* Out, int Amount, ...)
	{
		DWORD Result = Base;
		va_list Args;

		va_start(Args, Amount);

		DWORD Temp;
		for (int i = 0; i < Amount; i++)
		{
			ReadMemory(ProcessHandle, Result, &Temp, sizeof(Temp));
			Result = Temp + va_arg(Args, DWORD);
		}

		va_end(Args);
		if (Out)
		{
			ReadMemory(ProcessHandle, Result, Out, sizeof(T));
		}
		return Result;
	}

	//************************************
	// Method:    DerefPointer_s
	// Profit:	  Derefs a given MultiPointer
	// FullName:  SD_Tools::External<T>::DerefPointer_s
	// Returns:   DWORD the Adress of the last Deref
	// Notes:
	// -Returns NULL if one Deref failed
	//************************************
	template<typename T> DWORD SD_Tools::External::DerefPointer_s(HANDLE ProcessHandle, DWORD Base, T* Out, int Amount, ...)
	{
		DWORD Result = Base;
		va_list Args;

		va_start(Args, Amount);

		DWORD Temp;
		for (int i = 0; i < Amount; i++)
		{
			ReadMemory(ProcessHandle, Result, &Temp, sizeof(Temp));
			Result = Temp + va_arg(Args, DWORD);
			if (Result == NULL)
			{
				return 0;
			}
		}

		va_end(Args);
		if (Out)
		{
			ReadMemory(ProcessHandle, Result, Out, sizeof(T));
		}
		return Result;
	}



}





























